using System;
using System.Net;
using Cysharp.Threading.Tasks;
using GameFramework;
using GameFramework.Event;
using GameFramework.Fsm;
using GameFramework.GameServer;
using GameFramework.Json;
using GameFramework.Procedure.Attribute;
using GameFramework.Procedure.Fsm;
using GameFramework.Reference;
using GameFramework.Request;
using GameFramework.UI;
using GameFramework.UI.FairyGUI;
using GameFramework.WebServer;
using GameLogic.Launch;
using Server.Proto;
using UnityEngine;

namespace GameLogic.Login
{
    /// <summary>
    /// 登陆流程
    /// </summary>
    [Procedure]
    public sealed class LoginProcedure : AFsmProcedure
    {
        private bool m_Complete;

        public override void OnEnter(IFsm fsm)
        {
            base.OnEnter(fsm);
            m_Complete = false;
            EventService.That.Raise(this, LaunchStepUpdatedEvent.Acquire(LaunchStep.OpenLoginForm));
            EventService.That.Subscribe<RoleInfoNotify>(OnReceiveRoleInfoNotify);

            OpenLoginFormAsync().Forget();
        }

        public override void OnLeave(IFsm fsm)
        {
            base.OnLeave(fsm);
            
            EventService.That.Unsubscribe<RoleInfoNotify>(OnReceiveRoleInfoNotify);
        }

        private void OnReceiveRoleInfoNotify(object sender, EventArgs e)
        {
            var roleBasic = (RoleInfoNotify)e;
            Log.Info("Receive RoleInfoNotify: " + roleBasic.ToJson());
        }

        private async UniTask OpenLoginFormAsync()
        {
            // TODO Open Login Form

            m_Complete = true;
            EventService.That.Raise(this, LaunchStepUpdatedEvent.Acquire(LaunchStep.OpenLoginForm, 1f));

            DoLoginAsync().Forget();
        }

        private async UniTask DoLoginAsync()
        {
            var code = 0;
            while (true)
            {
                await UniTask.Yield();

                var authResp = await ReferenceService.That.GetReference<WebAuthReq>(req =>
                {
                    req.SDKType = LoginSDKType.Guest;
                    req.SDKUid = SystemInfo.deviceUniqueIdentifier;
                    req.SDKToken = SystemInfo.deviceUniqueIdentifier;
                    req.DeviceId = SystemInfo.deviceUniqueIdentifier;
                }).Execute<WebAuthResp>();
                using var _ = authResp.AutoRecycle();

                if (!authResp.IsSuccess())
                {
                    Log.Error(authResp.ToJson());
                    continue;
                }

                if (authResp.RecommendServer == null)
                {
                    Log.Error("RecommendServer is null");
                    continue;
                }

                code = await GameServerService.That.Connect(IPAddress.Parse(authResp.RecommendServer.Ip), authResp.RecommendServer.Port);
                Log.Info($"Connect to GameServer, code: {code}");

                if (code != 0)
                    continue;

                code = await ReferenceService.That.GetReference<LoginReq>(req =>
                {
                    req.Platform = GamePlatform.Windows;
                    req.DeviceId = SystemInfo.deviceUniqueIdentifier;
                    req.AccountId = authResp.AccountId;
                    req.LoginToken = authResp.LoginToken;
                }).SendToGameServer().PickCode();
                
                Log.Info($"Send LoginReq, code: {code}");
                
                if (code != 0)
                    continue;

                break;
            }
        }
    }
}